{
 "cells": [
  {
   "cell_type": "markdown",
   "source": [
    "## 配置数据DB"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "38b8b010a9c0efa8"
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "mysql\n",
      "['agent', 'agent_config', 'agent_dataset', 'ai_annotated_records', 'ai_messages_records', 'ai_provider', 'ai_provider_model', 'alembic_version', 'checkpoint_migrations', 'checkpoints', 'checkpoints_copy1', 'checkpoints_writes', 'conversations', 'datasets', 'documents', 'dws_resource_index', 'file_info', 'question_answer', 'unicom']\n"
     ]
    },
    {
     "data": {
      "text/plain": "{'table_info': '\\nCREATE TABLE agent (\\n\\tid VARCHAR(36) NOT NULL, \\n\\tsp_id VARCHAR(20) NOT NULL, \\n\\tname VARCHAR(255) NOT NULL, \\n\\tdescription TEXT NOT NULL, \\n\\ticon VARCHAR(255), \\n\\tagent_config_id VARCHAR(36), \\n\\tstatus VARCHAR(16) NOT NULL, \\n\\tenable_client TINYINT(1) NOT NULL, \\n\\tis_template TINYINT(1) NOT NULL DEFAULT \\'0\\', \\n\\tis_publish TINYINT(1) NOT NULL DEFAULT \\'0\\', \\n\\tagent_client_config TEXT, \\n\\tagent_type VARCHAR(36) NOT NULL, \\n\\tcreated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, \\n\\tupdated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, \\n\\tgraph_code VARCHAR(36), \\n\\tPRIMARY KEY (id)\\n)ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=\\'智能体\\'\\n\\n/*\\n3 rows from agent table:\\nid\\tsp_id\\tname\\tdescription\\ticon\\tagent_config_id\\tstatus\\tenable_client\\tis_template\\tis_publish\\tagent_client_config\\tagent_type\\tcreated_at\\tupdated_at\\tgraph_code\\n08cff3af1fb742ad88bbbc0f88118f2b\\t19080110203420013520\\t经分助手 3.0\\t用于发送短信的Agent\\t短信发送Agent\\t1e6ee430c925440d82ec23da9d6f0f3f\\tnormal\\t1\\t0\\t1\\tNone\\tCHAT\\t2024-09-10 11:40:36\\t2024-09-26 01:42:50\\tNone\\n097717bbbe1b4f5f87a3f8c02583dc54\\t123\\tDyric文本智能生成体\\t\\t\\t7060d68db6c5451faa2afb1ac0acfde1\\tdeleted\\t1\\t0\\t1\\tNone\\t3\\t2024-09-23 13:49:21\\t2024-09-26 01:42:00\\tNone\\n1234567890\\t230227193624036681\\t测试-demo\\t\\t\\t759f4c05f7cf40b59fde4c58abc769fe\\tnormal\\t1\\t0\\t0\\tNone\\tCHAT\\t2024-10-31 13:58:56\\t2024-10-31 13:58:56\\tNone\\n*/\\n\\n\\nCREATE TABLE agent_config (\\n\\tid VARCHAR(36) NOT NULL, \\n\\tagent_id VARCHAR(36) NOT NULL, \\n\\tprovider VARCHAR(255), \\n\\tmodel_id VARCHAR(255), \\n\\tcreated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, \\n\\tupdated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, \\n\\topening_statement TEXT, \\n\\topening_suggestion TEXT, \\n\\tmodel TEXT, \\n\\tprompt_variable TEXT, \\n\\tpre_prompt TEXT, \\n\\tenable_opening_statement TINYINT(1) NOT NULL DEFAULT \\'1\\', \\n\\tenable_suggested_questions TINYINT(1) NOT NULL DEFAULT \\'0\\', \\n\\tstatus VARCHAR(16) NOT NULL DEFAULT \\'normal\\', \\n\\tenable_datasets TINYINT(1) NOT NULL DEFAULT \\'0\\', \\n\\tdatasets TEXT, \\n\\tsuggested_graph_code VARCHAR(30) COMMENT \\'问题建议实现的graph\\', \\n\\tPRIMARY KEY (id)\\n)ENGINE=InnoDB DEFAULT CHARSET=utf8\\n\\n/*\\n3 rows from agent_config table:\\nid\\tagent_id\\tprovider\\tmodel_id\\tcreated_at\\tupdated_at\\topening_statement\\topening_suggestion\\tmodel\\tprompt_variable\\tpre_prompt\\tenable_opening_statement\\tenable_suggested_questions\\tstatus\\tenable_datasets\\tdatasets\\tsuggested_graph_code\\n1b1c9fa0769f424e9c965834fbfc312c\\tf7ce6a2811f141a7a94b44fe2d717b95\\tNone\\tNone\\t2024-09-03 13:56:33\\t2024-09-14 08:38:27\\t\\tNone\\t{\"completion_params\": {}, \"mode\": \"chat\", \"name\": \"gpt-4o\", \"provider\": \"openai\"}\\t[{\"key\": \"321312\", \"label\": \"sswww\", \"type\": 1}]\\t你是回答问题的助手。使用检索到的文档进行回答,如果无法从中得到答案，请说:“根据已知信息无法回答该问题” 或 “没有提供足够的相关信息”,不允许在答案中添加编造成分，答案要简洁\\t0\\t0\\tdeleted\\t0\\tNone\\tNone\\n1e6ee430c925440d82ec23da9d6f0f3f\\t08cff3af1fb742ad88bbbc0f88118f2b\\tNone\\tNone\\t2024-09-10 11:40:36\\t2024-09-24 05:42:37\\t我是你的短信发送助手\\tNone\\t{\"completion_params\": {}, \"mode\": \"chat\", \"name\": \"qwen-max\", \"provider\": \"tongyi\"}\\tNone\\t#上下文#\\n你帮助企业进行短信发送，需要用户提供:\\n1、发送的内容:是用户提供的一个完整的短信内容或者按照用户的要求帮他生成一个短信内容（70个字以内）\\n2、发送的对象:是一个或多个标签\\n3、发送规则\\t1\\t0\\tnormal\\t0\\tNone\\tNone\\n493fcb0896b84728889847c07b251721\\t37fffbc2825740b6aa3d6e14a2bf0726\\tNone\\tNone\\t2024-09-23 14:24:32\\t2024-09-26 01:41:53\\t您好，请问有什么可以帮助到您！\\tNone\\t{\"completion_params\": {}, \"mode\": \"chat\", \"name\": \"qwen-max\", \"provider\": \"tongyi\"}\\tNone\\t1.你是回答问题的助手。使用知识库中检索到的上下文进行回答,如果无法从中得到答案，请说:“根据已知信息无法回答该问题”\\xa0或\\xa0“没有提供足够的相关信息”,不允许在答案中添加编造成分，答案要简洁\\t1\\t0\\tdeleted\\t1\\t[\"d87f9f497e884a4fb854fd4f23bc41db\"]\\tNone\\n*/\\n\\n\\nCREATE TABLE agent_dataset (\\n\\tid VARCHAR(36) NOT NULL, \\n\\tagent_id VARCHAR(36) NOT NULL, \\n\\tdataset_id VARCHAR(36) NOT NULL, \\n\\tcreated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, \\n\\tPRIMARY KEY (id)\\n)ENGINE=InnoDB DEFAULT CHARSET=utf8\\n\\n/*\\n3 rows from agent_dataset table:\\nid\\tagent_id\\tdataset_id\\tcreated_at\\ndffaf24ec6a04764a19aca8c751247f1\\t86cdf4983f3f4a08843ce76c210718f0\\t54bd8ca268ce400ea65fbd743bbf17f7\\t2024-11-29 17:37:58\\ned4dc54b1013446f9f972d146ed2e178\\t97b44474c2cb4ad0a865399e3df7f2e4\\tb9ada881341746f7a6ededfcd6fc7c63\\t2024-12-04 15:06:18\\n*/\\n\\n\\nCREATE TABLE ai_annotated_records (\\n\\tid VARCHAR(36) NOT NULL, \\n\\tuser_input TEXT NOT NULL COMMENT \\'用户输入内容\\', \\n\\tai_answer TEXT NOT NULL COMMENT \\'智能体回答内容\\', \\n\\tai_agent_id VARCHAR(36) NOT NULL COMMENT \\'智能体标识\\', \\n\\tannotated_op INTEGER(1) NOT NULL COMMENT \\'标记动作:1 赞，2踩\\', \\n\\tanswer_type INTEGER(1) COMMENT \\'问答类型：1已知问题，2新问题\\', \\n\\t`optimize` TEXT COMMENT \\'调优信息\\', \\n\\treason_json VARCHAR(1024) COMMENT \\'不满意原因\\', \\n\\tsp_name VARCHAR(100) COMMENT \\'企业名称\\', \\n\\tsp_id VARCHAR(32) NOT NULL COMMENT \\'企业spID\\', \\n\\tstatus VARCHAR(16) NOT NULL COMMENT \\'normal,delete\\', \\n\\tcreated_by VARCHAR(36) NOT NULL COMMENT \\'创建人账号\\', \\n\\tcreated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, \\n\\tupdated_by VARCHAR(36) COMMENT \\'更新人帐号\\', \\n\\tupdated_at DATETIME COMMENT \\'更新时间\\' DEFAULT CURRENT_TIMESTAMP, \\n\\tai_message_record_id VARCHAR(36) COMMENT \\'智能体问答消息标识\\', \\n\\tcreated_by_name VARCHAR(200) COMMENT \\'创建人名称\\', \\n\\tquestion_answer_id VARCHAR(36) COMMENT \\'调优后生成的问答记录ID\\', \\n\\tconversation_id VARCHAR(36) COMMENT \\'AI会话ID\\', \\n\\tPRIMARY KEY (id)\\n)ENGINE=InnoDB DEFAULT CHARSET=utf8\\n\\n/*\\n3 rows from ai_annotated_records table:\\nid\\tuser_input\\tai_answer\\tai_agent_id\\tannotated_op\\tanswer_type\\toptimize\\treason_json\\tsp_name\\tsp_id\\tstatus\\tcreated_by\\tcreated_at\\tupdated_by\\tupdated_at\\tai_message_record_id\\tcreated_by_name\\tquestion_answer_id\\tconversation_id\\n01faa776132544cdbb5b0de2a17e468c\\t怎样查看短信发送记录？\\t对于怎样查看短信发送记录的问题，建议您可以查阅手机的使用说明书,或者咨询手机运营商的客服部门。希望这些建议能对您有所帮助。\\t86cdf4983f3f4a08843ce76c210718f0\\t2\\t1\\tNone\\t{\"reasons\":[\"不理解问题\",\"上下文错误\",\"格式错误\",\"逻辑混乱\"],\"other\":\"这个AI回答问题完全是打胡乱说的\"}\\tNone\\t19080110203420013520\\tnormal\\tLNI10230\\t2024-12-05 16:03:57\\tLNI10230\\t2024-12-05 16:03:57\\t0f408ef9c80f40bc91987236b84967f1\\t中云数赢云计算\\tNone\\t51315160436c4fc99000f3a34860ca22\\n0912b656f888421c9b1f2aee1bdd2575\\t怎样查看短信发送记录？\\t对于怎样查看短信发送记录的问题，建议您可以查阅手机的使用说明书,或者咨询手机运营商的客服部门。希望这些建议能对您有所帮助。\\tfe6e3c61d1a74b2bb0942f4404ca1234\\t2\\t2\\t对于怎样查看短信发送记录\\t{\"reasons\":[\"不理解问题\",\"上下文错误\",\"格式错误\",\"逻辑混乱\"],\"other\":\"这个AI回答问题完全是打胡乱说的\"}\\tNone\\t19080110203420013520\\tnormal\\tLNI10230\\t2024-11-19 14:37:21\\tLNI10230\\t2024-11-19 14:47:43\\td85a703a1a5d47d0b7629ce227278dc4\\t中云数赢云计算\\tNone\\tNone\\n109c25ccd74b40beb06622a12006a580\\t怎样查看短信发送记录？\\t对于怎样查看短信发送记录的问题，建议您可以查阅手机的使用说明书,或者咨询手机运营商的客服部门。希望这些建议能对您有所帮助。\\tfe6e3c61d1a74b2bb0942f4404ca1234\\t2\\t2\\tNone\\t\\tNone\\t19080110203420013520\\tnormal\\tLNI10230\\t2024-11-18 17:36:21\\tLNI10230\\t2024-11-18 17:36:21\\td85a703a1a5d47d0b7629ce227278dc4\\t中云数赢云计算\\tNone\\tNone\\n*/\\n\\n\\nCREATE TABLE ai_messages_records (\\n\\tid VARCHAR(36) NOT NULL, \\n\\tagent_id VARCHAR(36) NOT NULL, \\n\\tconversation_id VARCHAR(36) NOT NULL, \\n\\tpre_session_id VARCHAR(36) NOT NULL, \\n\\tinputs TEXT, \\n\\toutputs TEXT, \\n\\tinput_tokens INTEGER(11) NOT NULL, \\n\\toutput_tokens INTEGER(11) NOT NULL, \\n\\texecution_time VARCHAR(16) DEFAULT \\'0\\', \\n\\taccount_name VARCHAR(256) NOT NULL, \\n\\taccount_id VARCHAR(36) NOT NULL, \\n\\tsp_name VARCHAR(512) NOT NULL, \\n\\tsp_id VARCHAR(36) NOT NULL, \\n\\tstatus VARCHAR(16) NOT NULL DEFAULT \\'normal\\', \\n\\tcreated_by VARCHAR(36) NOT NULL, \\n\\tcreated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, \\n\\tupdated_at DATETIME NOT NULL, \\n\\tPRIMARY KEY (id)\\n)ENGINE=InnoDB DEFAULT CHARSET=utf8\\n\\n/*\\n3 rows from ai_messages_records table:\\nid\\tagent_id\\tconversation_id\\tpre_session_id\\tinputs\\toutputs\\tinput_tokens\\toutput_tokens\\texecution_time\\taccount_name\\taccount_id\\tsp_name\\tsp_id\\tstatus\\tcreated_by\\tcreated_at\\tupdated_at\\n00eeb9934b6c4c1a9b8da01988cd188f\\tfe6e3c61d1a74b2bb0942f202411271645\\t0cfe618593d147ef8ab68e09ef32a5ef\\te6184f9312ae418ebf3f0496dcf7f553\\t描述过去一周内每天标签使用的变化情况\\t{\"table_titles\": {\"date\": \"日期\", \"tag_name\": \"标签名称\", \"usage_count\": \"标签使用次数\"}, \"data\": [{\"date\": \"202\\t11594\\t666\\t24.088\\tPJY\\tBJS10160\\tPJY企业\\t230227193624162764\\tnormal\\tBJS10160\\t2024-12-05 10:57:00\\t0000-00-00 00:00:00\\n013e8d6b686141db80f2d8745535246b\\t4222e917e6b94c0a87f1da97d48d7290\\t1509b06cf45e4bb3b4564ce8c6009f82\\tbfe58f0e18e74eeab8971a5a6908d44c\\t\\t好的，我来帮您准备一条温馨的生日祝福短信给老师。为了确保这条短信既贴心又能准确传达您的祝福之情，我将基于一般情况下的良好实践来起草内容。同时，我会假设我们使用一个通用的签名，比如“来自[您的名字]”，\\t5185\\t535\\t26.706\\tPJY\\tBJS10160\\tPJY企业\\t230227193624162764\\tnormal\\tBJS10160\\t2024-12-04 16:27:32\\t0000-00-00 00:00:00\\n016690852393436b95ffb82a3bcb12ca\\tfe6e3c61d1a74b2bb0942f202411271645\\ta61bc9ceeb5a4245be04e19cfb18c389\\t14147b3ca1d44f3b85dc1c278fc1bea5\\t统计过去一个月内，不同省份（如北京、上海、广东等）发送短信的手机号的运营商分布情况\\t{\"table_titles\": {\"province\": \"省份\", \"operator\": \"运营商\", \"message_count\": \"短信数量\"}, \"data\": [{\"province\\t3484\\t342\\t17.920\\tPJY\\tBJS10160\\tPJY企业\\t230227193624162764\\tnormal\\tBJS10160\\t2024-12-05 15:27:26\\t0000-00-00 00:00:00\\n*/\\n\\n\\nCREATE TABLE ai_provider (\\n\\tid INTEGER(11) NOT NULL AUTO_INCREMENT, \\n\\tname VARCHAR(64) NOT NULL, \\n\\tcode VARCHAR(64), \\n\\ticon VARCHAR(255) NOT NULL, \\n\\tremark VARCHAR(255), \\n\\tmodel_from_schema_json TEXT, \\n\\tstatus VARCHAR(32) NOT NULL, \\n\\tcreated_by VARCHAR(32), \\n\\tcreated_at DATETIME NOT NULL, \\n\\tupdated_by VARCHAR(32), \\n\\tupdated_at DATETIME, \\n\\tPRIMARY KEY (id)\\n)ENGINE=InnoDB DEFAULT CHARSET=utf8\\n\\n/*\\n3 rows from ai_provider table:\\nid\\tname\\tcode\\ticon\\tremark\\tmodel_from_schema_json\\tstatus\\tcreated_by\\tcreated_at\\tupdated_by\\tupdated_at\\n1\\t通义千问\\tTongyiQwen\\thttps://flag-csv-v2.oss-cn-shanghai.aliyuncs.com/220913172204226327/2024-11-14/tongyiqianwen_2024111\\t通义千问\\t{\"test\": \"test\"}\\tnormal\\t\\t2024-11-11 14:05:41\\t\\t0000-00-00 00:00:00\\n2\\t智普\\tZhipu\\thttps://flag-csv-v2.oss-cn-shanghai.aliyuncs.com/220913172204226327/2024-11-14/zhipuAI_20241114_4208\\t智普\\t\\tnormal\\t\\t2024-11-11 14:08:51\\tNone\\tNone\\n*/\\n\\n\\nCREATE TABLE ai_provider_model (\\n\\tid INTEGER(11) NOT NULL AUTO_INCREMENT, \\n\\tmodel VARCHAR(255) NOT NULL, \\n\\tcode VARCHAR(255), \\n\\tname VARCHAR(255), \\n\\tprovider_id INTEGER(11) NOT NULL, \\n\\tremark TEXT, \\n\\tapi_key VARCHAR(255) NOT NULL, \\n\\tmax_token INTEGER(11), \\n\\tmax_context_len INTEGER(11), \\n\\tuse_count INTEGER(11), \\n\\tbelong_to VARCHAR(255), \\n\\tcall_url VARCHAR(255) NOT NULL, \\n\\tother_params_json TEXT, \\n\\tsp_name VARCHAR(255), \\n\\tsp_id VARCHAR(32), \\n\\tstatus VARCHAR(32) NOT NULL, \\n\\tcreated_by VARCHAR(32), \\n\\tcreated_at DATETIME NOT NULL, \\n\\tupdated_by VARCHAR(32), \\n\\tupdated_at DATETIME, \\n\\tPRIMARY KEY (id)\\n)ENGINE=InnoDB DEFAULT CHARSET=utf8\\n\\n/*\\n3 rows from ai_provider_model table:\\nid\\tmodel\\tcode\\tname\\tprovider_id\\tremark\\tapi_key\\tmax_token\\tmax_context_len\\tuse_count\\tbelong_to\\tcall_url\\tother_params_json\\tsp_name\\tsp_id\\tstatus\\tcreated_by\\tcreated_at\\tupdated_by\\tupdated_at\\n1\\tLLM\\tqwen-max\\t通义千问-Max\\t1\\t通义千问2.5系列千亿级别超大规模语言模型，支持中文、英文等不同语言输入。随着模型的升级，qwen-max将滚动更新升级。如果希望使用固定版本，请使用历史快照版本。\\tsk-6eb486c62f9349488fa406182a65d77b\\tNone\\tNone\\tNone\\t1\\t\\tNone\\tNone\\tNone\\tnormal\\tNone\\t2024-11-13 11:50:31\\tNone\\tNone\\n19\\tLLM\\tqwen-max-latest\\t通义千问-max-latest\\t1\\t本模型是动态更新版本，模型更新不会提前通知，适合复杂、多步骤的任务，模型中英文综合能力显著提升，模型人类偏好显著提升，模型推理能力和复杂指令理解能力显著增强，困难任务上的表现更优，数学、代码能力显著提\\tsk-6eb486c62f9349488fa406182a65d77b\\tNone\\tNone\\tNone\\t1\\t\\tNone\\tNone\\tNone\\tnormal\\tNone\\t0000-00-00 00:00:00\\tNone\\tNone\\n20\\tLLM\\tglm-4-flash\\t智谱-GLM-4-Flash\\t2\\t智谱AI首个免费大模型API，兼具“高速度”和“经济性”两大特点，支持128K上下文\\t4c1cd67a80b4ef01594c008537f40c13.MtTNRjjG78RboZ5w\\tNone\\tNone\\tNone\\t2\\t\\tNone\\tNone\\tNone\\tnormal\\tNone\\t0000-00-00 00:00:00\\tNone\\tNone\\n*/\\n\\n\\nCREATE TABLE alembic_version (\\n\\tversion_num VARCHAR(32) NOT NULL, \\n\\tPRIMARY KEY (version_num)\\n)ENGINE=InnoDB DEFAULT CHARSET=utf8\\n\\n/*\\n3 rows from alembic_version table:\\nversion_num\\n312694ccbe6a\\n*/\\n\\n\\nCREATE TABLE checkpoint_migrations (\\n\\tv INTEGER(11) NOT NULL, \\n\\tPRIMARY KEY (v)\\n)ENGINE=InnoDB DEFAULT CHARSET=utf8\\n\\n/*\\n3 rows from checkpoint_migrations table:\\nv\\n0\\n1\\n2\\n*/\\n\\n\\nCREATE TABLE checkpoints (\\n\\tthread_id VARCHAR(255) NOT NULL, \\n\\tcheckpoint_ns VARCHAR(255) NOT NULL DEFAULT \\'\\', \\n\\tcheckpoint_id VARCHAR(255) NOT NULL, \\n\\tparent_checkpoint_id VARCHAR(255), \\n\\ttype VARCHAR(255), \\n\\tcheckpoint BLOB, \\n\\tmetadata JSON, \\n\\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP, \\n\\tPRIMARY KEY (thread_id, checkpoint_ns, checkpoint_id)\\n)ENGINE=InnoDB DEFAULT CHARSET=utf8\\n\\n/*\\n3 rows from checkpoints table:\\nthread_id\\tcheckpoint_ns\\tcheckpoint_id\\tparent_checkpoint_id\\ttype\\tcheckpoint\\tmetadata\\tcreated_at\\nfa5f72a80b6e438fb54cd99713d0d792\\t\\t1efb3b30-de9a-6b32-bfff-810e7ee49522\\tNone\\tmsgpack\\tb\\'\\\\x87\\\\xa1v\\\\x01\\\\xa2ts\\\\xd9 2024-12-06T09:18:28.570835+00:00\\\\xa2id\\\\xd9$1efb3b30-de9a-6b32-bfff-810e7ee\\t{\\'step\\': -1, \\'source\\': \\'input\\', \\'writes\\': {\\'__start__\\': {\\'messages\\': [{\\'id\\': [\\'langchain\\', \\'schema\\',\\t2024-12-06 17:18:28\\nfa5f72a80b6e438fb54cd99713d0d792\\t\\t1efb3b30-debb-6a12-8000-b3f88ba85218\\t1efb3b30-de9a-6b32-bfff-810e7ee49522\\tmsgpack\\tb\\'\\\\x87\\\\xa1v\\\\x01\\\\xa2ts\\\\xd9 2024-12-06T09:18:28.584334+00:00\\\\xa2id\\\\xd9$1efb3b30-debb-6a12-8000-b3f88ba\\t{\\'step\\': 0, \\'source\\': \\'loop\\', \\'writes\\': None, \\'parents\\': {}, \\'agent_id\\': \\'fe6e3c61d1a74b2bb0942f2024\\t2024-12-06 17:18:29\\nfa5f72a80b6e438fb54cd99713d0d792\\t\\t1efb3b31-78ef-6f2a-8001-a3946e032f1f\\t1efb3b30-debb-6a12-8000-b3f88ba85218\\tmsgpack\\tb\\'\\\\x87\\\\xa1v\\\\x01\\\\xa2ts\\\\xd9 2024-12-06T09:18:44.753943+00:00\\\\xa2id\\\\xd9$1efb3b31-78ef-6f2a-8001-a3946e0\\t{\\'step\\': 1, \\'source\\': \\'loop\\', \\'writes\\': {\\'query_generate\\': {\\'messages\\': [{\\'id\\': [\\'langchain\\', \\'schem\\t2024-12-06 17:18:44\\n*/\\n\\n\\nCREATE TABLE checkpoints_copy1 (\\n\\tthread_id VARCHAR(255) NOT NULL, \\n\\tcheckpoint_ns VARCHAR(255) NOT NULL DEFAULT \\'\\', \\n\\tcheckpoint_id VARCHAR(255) NOT NULL, \\n\\tparent_checkpoint_id VARCHAR(255), \\n\\ttype VARCHAR(255), \\n\\tcheckpoint BLOB, \\n\\tmetadata JSON, \\n\\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP, \\n\\tPRIMARY KEY (thread_id, checkpoint_ns, checkpoint_id)\\n)ENGINE=InnoDB DEFAULT CHARSET=utf8\\n\\n/*\\n3 rows from checkpoints_copy1 table:\\nthread_id\\tcheckpoint_ns\\tcheckpoint_id\\tparent_checkpoint_id\\ttype\\tcheckpoint\\tmetadata\\tcreated_at\\n\\n*/\\n\\n\\nCREATE TABLE checkpoints_writes (\\n\\tthread_id VARCHAR(255) NOT NULL, \\n\\tcheckpoint_ns VARCHAR(255) NOT NULL DEFAULT \\'\\', \\n\\tcheckpoint_id VARCHAR(255) NOT NULL, \\n\\ttask_id VARCHAR(255) NOT NULL, \\n\\tidx INTEGER(11) NOT NULL, \\n\\tchannel VARCHAR(255) NOT NULL, \\n\\ttype VARCHAR(255), \\n\\tvalue BLOB, \\n\\tcreated_at DATETIME DEFAULT CURRENT_TIMESTAMP, \\n\\tPRIMARY KEY (thread_id, checkpoint_ns, checkpoint_id, task_id, idx)\\n)ENGINE=InnoDB DEFAULT CHARSET=utf8\\n\\n/*\\n3 rows from checkpoints_writes table:\\nthread_id\\tcheckpoint_ns\\tcheckpoint_id\\ttask_id\\tidx\\tchannel\\ttype\\tvalue\\tcreated_at\\nfa5f72a80b6e438fb54cd99713d0d792\\t\\t1efb3b30-de9a-6b32-bfff-810e7ee49522\\t42298c4a-ad2c-22dd-9501-f2548e994c32\\t0\\tmessages\\tmsgpack\\tb\\'\\\\x91\\\\xc7\\\\xe0\\\\x05\\\\x94\\\\xbdlangchain_core.messages.human\\\\xacHumanMessage\\\\x87\\\\xa7content\\\\xd9Q\\\\xe7\\\\xbb\\\\\\t2024-12-06 17:18:28\\nfa5f72a80b6e438fb54cd99713d0d792\\t\\t1efb3b30-de9a-6b32-bfff-810e7ee49522\\t42298c4a-ad2c-22dd-9501-f2548e994c32\\t1\\tstart:query_generate\\tmsgpack\\tb\\'\\\\xa9__start__\\'\\t2024-12-06 17:18:28\\nfa5f72a80b6e438fb54cd99713d0d792\\t\\t1efb3b30-debb-6a12-8000-b3f88ba85218\\tc56b5f14-6268-2f6f-e748-d3a13b83100c\\t0\\tquery_generate\\tmsgpack\\tb\\'\\\\xaequery_generate\\'\\t2024-12-06 17:18:44\\n*/\\n\\n\\nCREATE TABLE conversations (\\n\\tid VARCHAR(36) NOT NULL, \\n\\tagent_id VARCHAR(36) NOT NULL, \\n\\tagent_config_id VARCHAR(36), \\n\\tmodel_id VARCHAR(255), \\n\\tname VARCHAR(255) NOT NULL, \\n\\tinputs TEXT, \\n\\topening_statement TEXT, \\n\\tis_top TINYINT(1) NOT NULL DEFAULT \\'0\\', \\n\\tstatus VARCHAR(16) NOT NULL DEFAULT \\'normal\\', \\n\\tsp_id VARCHAR(36) NOT NULL, \\n\\tcreated_by VARCHAR(36) NOT NULL, \\n\\tcreated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, \\n\\tupdated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, \\n\\taccount_name VARCHAR(256) NOT NULL, \\n\\taccount_id VARCHAR(36) NOT NULL, \\n\\tsp_name VARCHAR(512) NOT NULL, \\n\\tPRIMARY KEY (id)\\n)ENGINE=InnoDB DEFAULT CHARSET=utf8\\n\\n/*\\n3 rows from conversations table:\\nid\\tagent_id\\tagent_config_id\\tmodel_id\\tname\\tinputs\\topening_statement\\tis_top\\tstatus\\tsp_id\\tcreated_by\\tcreated_at\\tupdated_at\\taccount_name\\taccount_id\\tsp_name\\n010a79a6839c48d5873008cd9dc0b547\\te28b39a3f1c0494493df96ff3330b88d\\tf1161410ed1841989342cf5123eaa042\\tNone\\t新会话\\tNone\\t你好，请问您遇到什么问题呢？\\t0\\tnormal\\t123\\tAB001\\t2024-09-18 13:51:55\\t2024-09-18 13:51:55\\t\\t\\t\\n010d05eab8ab43478440c7709c25b8be\\tfe6e3c61d1a74b2bb0942f202411251035\\tfe6e3c61d1a74b2bb0942f6543211234\\t1\\t新会话\\tNone\\tNone\\t0\\tnormal\\t19080110203420013520\\tLNI10230\\t2024-11-27 17:02:46\\t2024-11-27 17:02:46\\tLNI10230\\tLNI10230\\t中云数赢云计算\\n014dc904fe6a45de9dc838daabbc1cb6\\t4222e917e6b94c0a87f1da97d48d7290\\td30c65255f4e43c19725a0ef1a5af463\\t1\\t新会话\\tNone\\t我可以帮助你把已发送或经常发送的短信再次发送。\\t0\\tnormal\\t230227193624163513\\tBJS10173\\t2024-11-28 19:45:42\\t2024-11-28 19:45:42\\tBJS10173\\tBJS10173\\tXJL\\n*/\\n\\n\\nCREATE TABLE datasets (\\n\\tid VARCHAR(36) NOT NULL, \\n\\tname VARCHAR(255) NOT NULL, \\n\\tdescription TEXT, \\n\\tcollection_name VARCHAR(64), \\n\\tstatus VARCHAR(16) NOT NULL DEFAULT \\'normal\\', \\n\\tsp_id VARCHAR(36) NOT NULL, \\n\\tupdated_by VARCHAR(36) NOT NULL, \\n\\tcreated_by VARCHAR(36) NOT NULL, \\n\\tcreated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, \\n\\tupdated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, \\n\\tPRIMARY KEY (id)\\n)ENGINE=InnoDB DEFAULT CHARSET=utf8\\n\\n/*\\n3 rows from datasets table:\\nid\\tname\\tdescription\\tcollection_name\\tstatus\\tsp_id\\tupdated_by\\tcreated_by\\tcreated_at\\tupdated_at\\n0de8272fdbbe43dd912e7a55969ced6b\\t经分短信接口FAQ\\t用于短信接口对接的AI智能助手\\t1733292079898101\\tdeleted\\t19080110203420013520\\tLNI10230\\tLNI10230\\t2024-12-04 14:01:19\\t2024-12-04 06:10:49\\n3034a0fbe17c470db2dd7deca18e4588\\t知识库1\\t知识库1\\t1731649066508101\\tdeleted\\t19080110203420013520\\tLNI10230\\tLNI10230\\t2024-11-15 13:37:46\\t2024-11-15 05:38:12\\n54bd8ca268ce400ea65fbd743bbf17f7\\t知识库(勿删)\\t\\t1727073182043101\\tnormal\\t19080110203420013520\\tLNI10230\\tLNI10230\\t2024-09-23 14:33:20\\t2024-09-23 14:33:20\\n*/\\n\\n\\nCREATE TABLE documents (\\n\\tid VARCHAR(36) NOT NULL, \\n\\tname VARCHAR(255) NOT NULL, \\n\\tfile_id VARCHAR(512) NOT NULL, \\n\\tdataset_id VARCHAR(36) NOT NULL, \\n\\tword_count INTEGER(11) DEFAULT \\'0\\', \\n\\tenabled TINYINT(4) NOT NULL DEFAULT \\'1\\', \\n\\tstatus VARCHAR(16) NOT NULL DEFAULT \\'normal\\', \\n\\tsp_id VARCHAR(36) NOT NULL, \\n\\tcreated_by VARCHAR(36) NOT NULL, \\n\\tcreated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, \\n\\tupdated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, \\n\\tprocess_status VARCHAR(16) NOT NULL DEFAULT \\'pending\\', \\n\\tPRIMARY KEY (id)\\n)ENGINE=InnoDB DEFAULT CHARSET=utf8\\n\\n/*\\n3 rows from documents table:\\nid\\tname\\tfile_id\\tdataset_id\\tword_count\\tenabled\\tstatus\\tsp_id\\tcreated_by\\tcreated_at\\tupdated_at\\tprocess_status\\n047ba7b0569e430e9ed8cd5d9005ce25\\t短信模板规范5.pdf\\t1836287129606103040\\t9db8b6d2d1a8461989ff984617570601\\t749\\t1\\tdeleted\\t123\\tAB001\\t2024-09-20 16:40:35\\t2024-09-20 13:03:17\\tcompleted\\n06ea17be17cc434eb1e9b9e45bcbbff6\\t经分助手接口对接支撑操作手册.pdf\\t1838131303498383360\\t54bd8ca268ce400ea65fbd743bbf17f7\\t89421\\t1\\tdeleted\\t19080110203420013520\\tLNI10230\\t2024-09-23 16:21:30\\t2024-11-27 07:42:05\\textracting\\n09c066f6df6344cfbb74138314ac66af\\t短信发送FAQ.md\\t5433ca6bcc6b429dade4587cedc3cae2\\t7f11404a64904b0c86b52a34adadb173\\t11911\\t1\\tdeleted\\t19080110203420013520\\tLNI10230\\t2024-12-04 14:29:01\\t2024-12-04 06:33:55\\tcompleted\\n*/\\n\\n\\nCREATE TABLE dws_resource_index (\\n\\tsp_code VARCHAR(20) COMMENT \\'企业id\\', \\n\\tsp_name VARCHAR(20) COMMENT \\'企业名称\\', \\n\\tymd VARCHAR(100) COMMENT \\'天\\', \\n\\tagent_id VARCHAR(100) COMMENT \\'智能体id\\', \\n\\tagent_name VARCHAR(100) COMMENT \\'智能体\\', \\n\\tmodel_id VARCHAR(100) COMMENT \\'模型id\\', \\n\\tmodel_name VARCHAR(100) COMMENT \\'模型\\', \\n\\ttoken_num INTEGER(11) COMMENT \\'消耗token数\\' DEFAULT \\'0\\', \\n\\tcost DECIMAL(10, 2) COMMENT \\'费用\\'\\n)ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT=\\'资源概览\\'\\n\\n/*\\n3 rows from dws_resource_index table:\\nsp_code\\tsp_name\\tymd\\tagent_id\\tagent_name\\tmodel_id\\tmodel_name\\ttoken_num\\tcost\\n19080110203420013520\\t中云数赢云计算\\t2024-11-12\\tNone\\tNone\\tNone\\tNone\\t478\\t0.00\\n19080110203420013520\\t中云数赢云计算\\t2024-11-12\\t97b44474c2cb4ad0a865399e3df7f2e4\\t(勿删)经分助手智能客服\\tNone\\tNone\\t1967\\t0.00\\n19080110203420013520\\t中云数赢云计算\\t2024-11-12\\tfe6e3c61d1a74b2bb0942f4404ca1234\\t经分助手智能客户3.0\\t123\\tNone\\t8352\\t0.00\\n*/\\n\\n\\nCREATE TABLE file_info (\\n\\tid VARCHAR(32) NOT NULL COMMENT \\'企业id\\', \\n\\tsp_id VARCHAR(32) NOT NULL, \\n\\tname VARCHAR(256) NOT NULL, \\n\\tfile_id VARCHAR(32), \\n\\tfile_key VARCHAR(256) NOT NULL, \\n\\textension VARCHAR(32) NOT NULL, \\n\\tvendor VARCHAR(32) NOT NULL, \\n\\tfile_size INTEGER(11) DEFAULT \\'0\\', \\n\\tstatus VARCHAR(16) NOT NULL, \\n\\tcreated_by VARCHAR(32) NOT NULL, \\n\\tcreated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, \\n\\tPRIMARY KEY (id)\\n)ENGINE=InnoDB DEFAULT CHARSET=utf8\\n\\n/*\\n3 rows from file_info table:\\nid\\tsp_id\\tname\\tfile_id\\tfile_key\\textension\\tvendor\\tfile_size\\tstatus\\tcreated_by\\tcreated_at\\n002e5d6e3dbf48f6b2bb5fa5d8c3b029\\t19080110203420013520\\timage_7.jpg\\t002e5d6e3dbf48f6b2bb5fa5d8c3b029\\t19080110203420013520/9c4b8dd73fd74f5a89590eda0c43e40c-1733384649\\tjpg\\tminio\\t1574821\\tnormal\\tLNI10230\\t2024-12-05 07:44:10\\n0febf6e52db44f77aae4ad7c4c59e335\\t19080110203420013520\\t短信发送FAQ.md\\t0febf6e52db44f77aae4ad7c4c59e335\\t19080110203420013520/708b8251af314b36a2a5b1a0a15ab629-1733390550\\tmd\\tminio\\t18657\\tnormal\\tLNI10230\\t2024-12-05 09:22:31\\n1838111317698543616\\t19080110203420013520\\t短信发送FAQ.pdf\\t1838111317698543616\\tcloud_disk/pub/230227193624163513/biz/1838111317698543616\\tpdf\\tcloud_disk\\t11270707\\tnormal\\tLNI10230\\t2024-11-21 18:41:22\\n*/\\n\\n\\nCREATE TABLE question_answer (\\n\\tid VARCHAR(36) NOT NULL, \\n\\tsp_id VARCHAR(36) NOT NULL COMMENT \\'企业id\\', \\n\\tdataset_id VARCHAR(36) NOT NULL COMMENT \\'知识库id\\', \\n\\tquestion TEXT NOT NULL COMMENT \\'问题\\', \\n\\tanswer TEXT NOT NULL COMMENT \\'答案\\', \\n\\tsource TEXT COMMENT \\'来源json数组\\', \\n\\tenable TINYINT(1) NOT NULL COMMENT \\'停用启用\\' DEFAULT \\'0\\', \\n\\tstatus VARCHAR(16) NOT NULL COMMENT \\'normal,delete\\' DEFAULT \\'normal\\', \\n\\tcreated_by VARCHAR(36) NOT NULL COMMENT \\'创建人账号\\', \\n\\tcreated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, \\n\\tupdated_by VARCHAR(36) NOT NULL, \\n\\tupdated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, \\n\\tPRIMARY KEY (id)\\n)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4\\n\\n/*\\n3 rows from question_answer table:\\nid\\tsp_id\\tdataset_id\\tquestion\\tanswer\\tsource\\tenable\\tstatus\\tcreated_by\\tcreated_at\\tupdated_by\\tupdated_at\\n000a26ff381241468c03be7a7d1b9334\\t19080110203420013520\\tb9ada881341746f7a6ededfcd6fc7c63\\t在使用sendBatch接口时遇到了什么问题？\\t在使用sendBatch接口加上动态签名进行批量发送时出现了错误。\\t{\"page_content\": \"\", \"metadata\": {\"source\": \"短信发送FAQ.md\", \"source_type\": \"document_extract\"}}\\t1\\tnormal\\tLNI10230\\t2024-12-05 17:40:16\\tLNI10230\\t2024-12-05 17:40:16\\n003f350c4ea04ce1bea3dd8f9adb9a37\\t19080110203420013520\\t7f11404a64904b0c86b52a34adadb173\\t使用https协议请求一信通接口与使用http协议有何不同？\\t使用https协议的主要区别在于数据传输的安全性更高。https通过SSL/TLS加密技术保护数据，防止敏感信息（如账号密码）在传输过程中被窃取。此外，一些服务可能只支持https请求，以确保通信的安\\t{\"page_content\": \"\", \"metadata\": {\"source\": \"短信发送FAQ.md\", \"source_type\": \"document_extract\"}}\\t1\\tnormal\\tLNI10230\\t2024-12-04 14:35:13\\tLNI10230\\t2024-12-04 14:35:13\\n00413a001d6045f483416f96b11e2cc9\\t19080110203420013520\\t7f11404a64904b0c86b52a34adadb173\\t如何解决这个问题？\\t可以通过对字符串中的双引号进行转义来解决此问题。例如，将字符串中的每个双引号替换为 \\\\\\\\\" 。这样，JSON 解析器就能正确解析数据了。\\t{\"page_content\": \"\", \"metadata\": {\"source\": \"短信发送FAQ.md\", \"source_type\": \"document_extract\"}}\\t1\\tnormal\\tLNI10230\\t2024-12-04 14:30:39\\tLNI10230\\t2024-12-04 14:30:39\\n*/\\n\\n\\nCREATE TABLE unicom (\\n\\tid INTEGER(11) UNSIGNED NOT NULL COMMENT \\'主键ID\\' AUTO_INCREMENT, \\n\\tcity VARCHAR(255) COMMENT \\'城市\\', \\n\\tproduct_name VARCHAR(255) COMMENT \\'产品名称\\', \\n\\tincome INTEGER(11) COMMENT \\'收入\\', \\n\\tsales_name VARCHAR(255) COMMENT \\'销售名称\\', \\n\\tsales_channel VARCHAR(255) COMMENT \\'销售渠道\\', \\n\\tbusiness VARCHAR(255) COMMENT \\'业务\\', \\n\\tsubmit_date DATETIME COMMENT \\'提交日期\\', \\n\\tPRIMARY KEY (id)\\n)ENGINE=InnoDB DEFAULT CHARSET=utf8\\n\\n/*\\n3 rows from unicom table:\\nid\\tcity\\tproduct_name\\tincome\\tsales_name\\tsales_channel\\tbusiness\\tsubmit_date\\n1\\t宝鸡\\t公播音乐\\t50\\t谢超\\t太白集团直销团队\\t云计算\\t2024-03-30 00:00:00\\n2\\t宝鸡\\t公播音乐\\t750\\t谢超\\t太白集团直销团队\\t云计算\\t2024-03-30 00:00:00\\n3\\t宝鸡\\t公播音乐\\t9600\\t谢超\\t太白集团直销团队\\t云计算\\t2024-03-30 00:00:00\\n*/',\n 'table_names': 'agent, agent_config, agent_dataset, ai_annotated_records, ai_messages_records, ai_provider, ai_provider_model, alembic_version, checkpoint_migrations, checkpoints, checkpoints_copy1, checkpoints_writes, conversations, datasets, documents, dws_resource_index, file_info, question_answer, unicom'}"
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_community.utilities import SQLDatabase\n",
    "\n",
    "db = SQLDatabase.from_uri(\"mysql+pymysql://zx_ai_unicom:zx_ai#5402_unicom@58.247.254.164:3306/zx_ai\")#(\"sqlite:///../../lang_chain/cookbook/Chinook.db\")\n",
    "print(db.dialect)\n",
    "print(db.get_usable_table_names())\n",
    "db.get_context()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-12-06T09:42:54.791520Z",
     "start_time": "2024-12-06T09:42:45.422311Z"
    }
   },
   "id": "44833a54410cface",
   "execution_count": 1
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 工具调用异常代理\n",
    "定义一个函数来来包装ToolNode，以处理错误并将错误消息返回给代理。"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "8f9a11966a3e7571"
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [
    "\n",
    "from langchain_core.messages import ToolMessage\n",
    "from typing import Any\n",
    "from langchain_core.runnables import RunnableLambda, RunnableWithFallbacks\n",
    "from langgraph.prebuilt import ToolNode\n",
    "\n",
    "\n",
    "def create_tool_node_with_fallback(tools: list) -> RunnableWithFallbacks[Any, dict]:\n",
    "    \"\"\"\n",
    "    创建一个具有回退功能的ToolNode来处理错误并将其显示给代理。\n",
    "    \"\"\"\n",
    "    return ToolNode(tools).with_fallbacks(\n",
    "        [RunnableLambda(handle_tool_error)], exception_key=\"error\"\n",
    "    )\n",
    "\n",
    "\n",
    "def handle_tool_error(state) -> dict:\n",
    "    error = state.get(\"error\")\n",
    "    tool_calls = state[\"messages\"][-1].tool_calls\n",
    "    return {\n",
    "        \"messages\": [\n",
    "            ToolMessage(\n",
    "                content=f\"Error: {repr(error)}\\n please fix your mistakes.\",\n",
    "                tool_call_id=tc[\"id\"],\n",
    "            )\n",
    "            for tc in tool_calls\n",
    "        ]\n",
    "    }"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-12-06T09:42:56.159718Z",
     "start_time": "2024-12-06T09:42:54.796970Z"
    }
   },
   "id": "b6511b0b14d0d759",
   "execution_count": 2
  },
  {
   "cell_type": "markdown",
   "source": [
    "## 定义工具\n",
    "使用langchain_community包中的`QuerySQLDataBaseTool` `InfoSQLDatabaseTool` `ListSQLDatabaseTool` `QuerySQLCheckerTool`\n",
    "### 获取表名"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "4fd77cfad46bd712"
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [
    "import logging\n",
    "from typing import List, Type, Optional, Union, Sequence, Dict, Any\n",
    "\n",
    "from langchain_community.tools import ListSQLDatabaseTool, InfoSQLDatabaseTool, \\\n",
    "    BaseSQLDatabaseTool\n",
    "from langchain_community.utilities import SQLDatabase\n",
    "from langchain_core.callbacks import CallbackManagerForToolRun\n",
    "from langchain_core.tools import BaseToolkit, BaseTool, tool\n",
    "from pydantic import Field, ConfigDict, BaseModel\n",
    "from sqlalchemy import Result\n",
    "from sqlvalidator import parse\n",
    "\n",
    "\n",
    "class SQLDatabaseJFToolkit(BaseToolkit):\n",
    "    \"\"\"SQL Database Toolkit\"\"\"\n",
    "    db: SQLDatabase = Field(exclude=True)\n",
    "    model_config = ConfigDict(\n",
    "        arbitrary_types_allowed=True,\n",
    "    )\n",
    "\n",
    "    @property\n",
    "    def dialect(self) -> str:\n",
    "        \"\"\"Return string representation of SQL dialect to use.\"\"\"\n",
    "        return self.db.dialect\n",
    "\n",
    "    def get_tools(self) -> List[BaseTool]:\n",
    "        \"\"\"Get the tools in the toolkit.\"\"\"\n",
    "        list_sql_database_tool = ListSQLDatabaseTool(db=self.db)\n",
    "        # info_sql_database_tool_description = (\n",
    "        #     \"Input to this tool is a comma-separated list of tables, output is the \"\n",
    "        #     \"schema and sample rows for those tables. \"\n",
    "        #     \"Be sure that the tables actually exist by calling \"\n",
    "        #     f\"{list_sql_database_tool.name} first! \"\n",
    "        #     \"Example Input: table1, table2, table3\"\n",
    "        # )\n",
    "        info_sql_database_tool = InfoSQLDatabaseTool(\n",
    "            db=self.db,\n",
    "        )\n",
    "        # query_sql_database_tool_description = (\n",
    "        #     \"Input to this tool is a detailed and correct SQL query, output is a \"\n",
    "        #     \"result from the database. If the query is not correct, an error message \"\n",
    "        #     \"will be returned. If an error is returned, rewrite the query, check the \"\n",
    "        #     \"query, and try again. If you encounter an issue with Unknown column \"\n",
    "        #     f\"'xxxx' in 'field list', use {info_sql_database_tool.name} \"\n",
    "        #     \"to query the correct table fields.\"\n",
    "        # )\n",
    "        query_sql_database_tool = QuerySQLDataBaseTool(\n",
    "            db=self.db,\n",
    "            include_columns=True,\n",
    "        )\n",
    "\n",
    "        return [\n",
    "            query_sql_database_tool,\n",
    "            info_sql_database_tool,\n",
    "            list_sql_database_tool,\n",
    "            sql_db_query_checker,\n",
    "        ]\n",
    "\n",
    "    def get_context(self) -> dict:\n",
    "        \"\"\"Return db context that you may want in agent prompt.\"\"\"\n",
    "        return self.db.get_context()\n",
    "\n",
    "class _QuerySQLDataBaseToolInput(BaseModel):\n",
    "    query: str = Field(..., description=\"A detailed and correct SQL query.\")\n",
    "    col_desc:dict[str, str] = Field(...,description=\"column description for query result.\")\n",
    "\n",
    "class QuerySQLDataBaseTool(BaseSQLDatabaseTool, BaseTool):\n",
    "    \"\"\"Tool for querying a SQL database.\"\"\"\n",
    "\n",
    "    name: str = \"sql_db_query\"\n",
    "    include_columns: bool = False\n",
    "    description: str = \"\"\"\n",
    "    Execute a SQL query against the database and get back the result..\n",
    "    If the query is not correct, an error message will be returned.\n",
    "    If an error is returned, rewrite the query, check the query, and try again.\n",
    "    \"\"\"\n",
    "    args_schema: Type[BaseModel] = _QuerySQLDataBaseToolInput\n",
    "\n",
    "    def _run(\n",
    "        self,\n",
    "        query: str,\n",
    "        col_desc:Optional[dict[str, str]]=None,\n",
    "        run_manager: Optional[CallbackManagerForToolRun] = None,\n",
    "    ) -> Union[str, Sequence[Dict[str, Any]], Result]:\n",
    "        \"\"\"Execute the query, return the results or an error message.\"\"\"\n",
    "        print(f\"col_desc: {col_desc}\" )\n",
    "        return self.db.run_no_throw(query, include_columns=self.include_columns)\n",
    "\n",
    "@tool\n",
    "def sql_db_query_checker(query: str) -> bool:\n",
    "    \"\"\"调用sql_db_query之前检查输入的SQL查询是否正确\"\"\"\n",
    "    # SQL验证未与DB链接相关，因此，该工具定义使用那种方式均可\n",
    "    logging.debug(f\"checking query: {query}\")\n",
    "    result = parse(query)\n",
    "    if not result.is_valid():\n",
    "        logging.error(f\"query is not valid: {result.errors}\")\n",
    "    return result.is_valid()\n",
    "\n",
    "# list_tables_tool = ListSQLDatabaseTool(db=db)\n",
    "# list_tables_tool.invoke(\"Customer\")"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-12-06T09:42:56.229861Z",
     "start_time": "2024-12-06T09:42:56.162637Z"
    }
   },
   "id": "f69658d9076fa9e",
   "execution_count": 3
  },
  {
   "cell_type": "markdown",
   "source": [
    "### 获取表结构\n"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "f30093c456c9985b"
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "\"\\nCREATE TABLE unicom (\\n\\tid INTEGER(11) UNSIGNED NOT NULL COMMENT '主键ID' AUTO_INCREMENT, \\n\\tcity VARCHAR(255) COMMENT '城市', \\n\\tproduct_name VARCHAR(255) COMMENT '产品名称', \\n\\tincome INTEGER(11) COMMENT '收入', \\n\\tsales_name VARCHAR(255) COMMENT '销售名称', \\n\\tsales_channel VARCHAR(255) COMMENT '销售渠道', \\n\\tbusiness VARCHAR(255) COMMENT '业务', \\n\\tsubmit_date DATETIME COMMENT '提交日期', \\n\\tPRIMARY KEY (id)\\n)ENGINE=InnoDB DEFAULT CHARSET=utf8\\n\\n/*\\n3 rows from unicom table:\\nid\\tcity\\tproduct_name\\tincome\\tsales_name\\tsales_channel\\tbusiness\\tsubmit_date\\n1\\t宝鸡\\t公播音乐\\t50\\t谢超\\t太白集团直销团队\\t云计算\\t2024-03-30 00:00:00\\n2\\t宝鸡\\t公播音乐\\t750\\t谢超\\t太白集团直销团队\\t云计算\\t2024-03-30 00:00:00\\n3\\t宝鸡\\t公播音乐\\t9600\\t谢超\\t太白集团直销团队\\t云计算\\t2024-03-30 00:00:00\\n*/\""
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\n",
    "sql_db_toolkit = SQLDatabaseJFToolkit(db=db)\n",
    "\n",
    "get_schema_tool = next(tool for tool in sql_db_toolkit.get_tools() if tool.name == \"sql_db_schema\")\n",
    "get_schema_tool.invoke(\"unicom\")"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-12-06T09:42:56.430024Z",
     "start_time": "2024-12-06T09:42:56.231424Z"
    }
   },
   "id": "67de84dc801e7fbb",
   "execution_count": 4
  },
  {
   "cell_type": "markdown",
   "source": [
    "### sql checker"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "cb2803a7e4f13c21"
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "True"
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_community.chat_models import ChatTongyi\n",
    "from pydantic import BaseModel\n",
    "from pydantic import Field\n",
    "from langchain_core.messages import AIMessage\n",
    "import os\n",
    "from dotenv import load_dotenv\n",
    "from langchain_community.tools import QuerySQLCheckerTool\n",
    "from typing import Annotated, Literal\n",
    "\n",
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "from typing_extensions import TypedDict\n",
    "\n",
    "from langgraph.graph.message import AnyMessage, add_messages\n",
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "\n",
    "\n",
    "class State(TypedDict):\n",
    "    messages: Annotated[list[AnyMessage], add_messages]\n",
    "\n",
    "\n",
    "load_dotenv()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-12-06T09:42:57.279232Z",
     "start_time": "2024-12-06T09:42:56.435669Z"
    }
   },
   "id": "914d377726d2960c",
   "execution_count": 5
  },
  {
   "cell_type": "markdown",
   "source": [
    "### 执行SQL查询"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "76d5ab5d6613f644"
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'properties': {'query': {'description': 'A detailed and correct SQL query.', 'title': 'Query', 'type': 'string'}, 'col_desc': {'additionalProperties': {'type': 'string'}, 'description': 'column description for query result.', 'title': 'Col Desc', 'type': 'object'}}, 'required': ['query', 'col_desc'], 'title': '_QuerySQLDataBaseToolInput', 'type': 'object'}\n"
     ]
    }
   ],
   "source": [
    "\n",
    "sql_db_query_tool = next(tool for tool in sql_db_toolkit.get_tools() if tool.name == \"sql_db_query\")\n",
    "#result = sql_db_query_tool.invoke(\"select * from unicom limit 2\",None)\n",
    "# result\n",
    "print(sql_db_query_tool.args_schema.schema())# sql_db_query_tool.name"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-12-06T09:42:57.289324Z",
     "start_time": "2024-12-06T09:42:57.281330Z"
    }
   },
   "id": "63f68dd075591614",
   "execution_count": 6
  },
  {
   "cell_type": "markdown",
   "source": [],
   "metadata": {
    "collapsed": false
   },
   "id": "e078da06b7cdc403"
  },
  {
   "cell_type": "markdown",
   "source": [
    "## workflow"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "3aa28fe9bdefbe9c"
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "{'messages': [AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_dbb75d8655754112b51858', 'function': {'arguments': '{\"query\": \"SELECT id, name, description, created_at FROM agent ORDER BY created_at DESC LIMIT 5;\", \"col_desc\": {\"id\": \"智能体ID\", \"name\": \"智能体名称\", \"description\": \"描述\", \"created_at\": \"创建时间\"}}', 'name': 'sql_query'}, 'type': 'function', 'index': 0}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 69, 'prompt_tokens': 11463, 'total_tokens': 11532, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_name': 'qwen-max', 'system_fingerprint': None, 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-dc78c5bb-d02e-4d21-9506-c252d2ce433c-0', tool_calls=[{'name': 'sql_query', 'args': {'query': 'SELECT id, name, description, created_at FROM agent ORDER BY created_at DESC LIMIT 5;', 'col_desc': {'id': '智能体ID', 'name': '智能体名称', 'description': '描述', 'created_at': '创建时间'}}, 'id': 'call_dbb75d8655754112b51858', 'type': 'tool_call'}], usage_metadata={'input_tokens': 11463, 'output_tokens': 69, 'total_tokens': 11532, 'input_token_details': {}, 'output_token_details': {}})]}"
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain.agents import tools\n",
    "from langchain_core.prompts import ChatPromptTemplate\n",
    "from typing import Annotated, Literal\n",
    "\n",
    "from langchain_core.messages import AIMessage\n",
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "from pydantic import BaseModel, Field\n",
    "from typing_extensions import TypedDict\n",
    "\n",
    "from langgraph.graph import END, StateGraph, START\n",
    "from langgraph.graph.message import AnyMessage, add_messages\n",
    "\n",
    "\n",
    "def load_tables_schema_tool_call_node(state: State, config) -> dict[str, list[AIMessage]]:\n",
    "    return {\n",
    "        \"messages\": [\n",
    "            AIMessage(\n",
    "                content=\"\",\n",
    "                tool_calls=[\n",
    "                    {\n",
    "                        \"name\": get_schema_tool.name,\n",
    "                        \"args\": {\"table_names\": \"agent,ai_provider\"},\n",
    "                        #{\"table_names\": state[\"messages\"][-1].tool_calls[0].args[\"table_names\"]},\n",
    "                        \"id\": \"tool_abcd124\",\n",
    "                    }\n",
    "                ]\n",
    "            )\n",
    "        ]\n",
    "    }\n",
    "from langchain_core.tools import tool\n",
    "\n",
    "@tool\n",
    "def sql_query(query:str,col_desc:dict[str, str]):\n",
    "    \"\"\"执行SQL查询\"\"\"\n",
    "    print(f\"query: {query}, cols: {col_desc}\")\n",
    "# SQL语句生成\n",
    "def query_generate_node(state: State, config):\n",
    "    \"\"\"SQL语句生成\"\"\"\n",
    "    dialect = db.dialect\n",
    "    limit = 5\n",
    "    table_info_dict = sql_db_toolkit.get_context()\n",
    "    table_info = table_info_dict[\"table_info\"]\n",
    "    #不要使用除SubmitFinalAnswer之外的任何工具来提交最终答案，最终答案只返回查询语句。\n",
    "    query_generate_template = f\"\"\"你是一个注重细节的SQL专家。\n",
    "    \n",
    "    给定一个问题，输出一个语法正确的{dialect}查询语句，然后返回查询语句、查询语句返回列对应描述。\n",
    "    \n",
    "    不要使用工具来提交最终答案，最终答案只返回查询语句。\n",
    "    \n",
    "    在生成查询时：\n",
    "        \n",
    "    除非用户指定了他们希望获得的具体示例数量，否则应始终将查询结果限制在最多{limit}个。 可以根据相关列对结果进行排序，以返回数据库中最佳的示例。 永远不要查询特定表中的所有列，只根据问题要求查询相关列。\n",
    "    \n",
    "    如果在执行查询时出现错误，请重写查询并再次尝试。\n",
    "    \n",
    "    如果生成的查询返回包含created_at，应尝试将其按{dialect}方言格式化为年月日时分秒\n",
    "\n",
    "    如果得到空的结果集，应尝试重写查询以获得非空的结果集。 如果没有足够的信息来回答查询，千万不要编造答案...只需说明你没有足够的信息。\n",
    "    \n",
    "    如果你有足够的信息来回答输入的问题，只需调用适当的工具将最终答案提交给用户。\n",
    "    不要对数据库执行任何DML语句（如INSERT、UPDATE、DELETE、DROP等）。\n",
    "    \"\"\"\n",
    "    #     如果表字段中存在'Email'字段，请将该表查询条件增加'Email'等于'122@123.com'条件\n",
    "\n",
    "    query_generate_prompt = ChatPromptTemplate.from_messages(\n",
    "        [(\"system\", query_generate_template+\"{table_info}\"), (\"placeholder\", \"{messages}\")]\n",
    "    )\n",
    "    \n",
    "    llm = query_generate_prompt | ChatOpenAI(\n",
    "        # 若没有配置环境变量，请用百炼API Key将下行替换为：api_key=\"sk-xxx\",\n",
    "        openai_api_key=os.getenv(\"DASHSCOPE_API_KEY\"),\n",
    "        openai_api_base=\"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n",
    "        model_name=\"qwen-max\",\n",
    "        verbose=True, temperature=0\n",
    "    ).bind_tools([sql_query])\n",
    "    # llm = query_generate_prompt | ChatTongyi(\n",
    "    #     # 若没有配置环境变量，请用百炼API Key将下行替换为：api_key=\"sk-xxx\",\n",
    "    #     api_key=os.getenv(\"DASHSCOPE_API_KEY\"),\n",
    "    #     # openai_api_base=\"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n",
    "    #     model=\"qwen-max\",\n",
    "    #     top_p=0.9,\n",
    "    #     verbose=True, temperature=0.5\n",
    "    # ).bind_tools([sql_db_query_tool])\n",
    "\n",
    "    message = llm.invoke({**{\"table_info\": table_info},**state})\n",
    "\n",
    "    return {\"messages\": [message] }\n",
    "\n",
    "query_generate_node({\"messages\": [(\"user\", \"最近创建的智能体\")]}, None)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-12-06T09:43:13.153138Z",
     "start_time": "2024-12-06T09:42:57.291164Z"
    }
   },
   "id": "bb50b08d9aa43a1d",
   "execution_count": 7
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [
    "from langgraph.checkpoint.memory import MemorySaver\n",
    "from langchain_core.messages import RemoveMessage\n",
    "\n",
    "workflow = StateGraph(State)\n",
    "# workflow.add_node(\"tables_schema_tool_call\", load_tables_schema_tool_call_node)\n",
    "# workflow.add_node(\"schema_tool\", create_tool_node_with_fallback([get_schema_tool]))\n",
    "workflow.add_node(\"query_generate\", query_generate_node)\n",
    "workflow.add_node(\"query_execute_tools\", create_tool_node_with_fallback([sql_db_query_tool]))\n",
    "\n",
    "# 条件边，检查sql有效性\n",
    "def should_continue_with_schema(state) -> Literal[END, \"query_generate\"]:\n",
    "    \"\"\"判断是否需要加载表结构是否正常\"\"\"\n",
    "    last_message = state[\"messages\"][-1]\n",
    "    if not last_message.content.startswith(\"Error:\"):\n",
    "        return \"query_generate\"\n",
    "    else:\n",
    "        return END\n",
    "def should_continue_with_query(state) -> Literal[END, \"query_execute_tools\", \"query_generate\"]:\n",
    "    \"\"\"判断是否继续执行下一步操作\"\"\"\n",
    "    # todo 待完善\n",
    "    messages = state[\"messages\"]\n",
    "    last_message = messages[-1]\n",
    "    # If there is a tool call, then we finish\n",
    "    if last_message.tool_calls:\n",
    "        print(f\"should_continue_with_query:query_execute_tools\")\n",
    "        return \"query_execute_tools\"\n",
    "    if last_message.content.startswith(\"Error:\"):\n",
    "        print(f\"should_continue_with_query:query_generate\")\n",
    "        return \"query_generate\"\n",
    "    else:\n",
    "        print(f\"should_continue_with_query:END\")\n",
    "        return END\n",
    "    \n",
    "    \n",
    "def delete_messages(state):\n",
    "    messages = state[\"messages\"]\n",
    "    if len(messages) > 3:\n",
    "        print(f\"delete_messages: {len(messages)}\")\n",
    "        return {\"messages\": [RemoveMessage(id=m.id) for m in messages[:-3]]}\n",
    "\n",
    "workflow.add_node(\"delete_messages\",delete_messages)\n",
    "\n",
    "\n",
    "# 边\n",
    "# workflow.add_edge(START, \"tables_schema_tool_call\")\n",
    "# workflow.add_edge(\"tables_schema_tool_call\", \"schema_tool\")\n",
    " # 边策略\n",
    "# workflow.add_conditional_edges(\"schema_tool\",should_continue_with_schema)\n",
    "workflow.add_edge(START, \"query_generate\")\n",
    "\n",
    "workflow.add_conditional_edges(\"query_generate\",should_continue_with_query)\n",
    "workflow.add_edge(\"query_execute_tools\", \"delete_messages\")\n",
    "workflow.add_edge(\"delete_messages\", END)\n",
    "memory_saver = MemorySaver()\n",
    "graph = workflow.compile(checkpointer=memory_saver)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-12-06T09:53:08.359573Z",
     "start_time": "2024-12-06T09:53:08.343156Z"
    }
   },
   "id": "705eb2a4a422c4aa",
   "execution_count": 21
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "image/jpeg": "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",
      "text/plain": "<IPython.core.display.Image object>"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import Image, display\n",
    "from langchain_core.runnables.graph import MermaidDrawMethod\n",
    "\n",
    "display(\n",
    "    Image(\n",
    "        graph.get_graph().draw_mermaid_png(\n",
    "            draw_method=MermaidDrawMethod.API,\n",
    "        )\n",
    "    )\n",
    ")"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-12-06T09:53:10.795284Z",
     "start_time": "2024-12-06T09:53:10.032296Z"
    }
   },
   "id": "5303410dbfc0e181",
   "execution_count": 22
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "should_continue_with_query:query_execute_tools\n",
      "Event:{'query_generate': {'messages': [AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_811333299a1d440e91c9a7', 'function': {'arguments': '{\"query\": \"SELECT id, sp_id, name, description, status, DATE_FORMAT(created_at, \\'%Y-%m-%d %H:%i:%s\\') as created_at FROM agent ORDER BY created_at DESC LIMIT 5;\", \"col_desc\": {\"id\": \"\\\\u667a\\\\u80fd\\\\u4f53ID\", \"sp_id\": \"\\\\u4f01\\\\u4e1aID\", \"name\": \"\\\\u667a\\\\u80fd\\\\u4f53\\\\u540d\\\\u79f0\", \"description\": \"\\\\u63cf\\\\u8ff0\", \"status\": \"\\\\u72b6\\\\u6001\", \"created_at\": \"\\\\u521b\\\\u5efa\\\\u65f6\\\\u95f4\"}}', 'name': 'sql_db_query'}, 'type': 'function', 'index': 0}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 182, 'prompt_tokens': 11698, 'total_tokens': 11880, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'model_name': 'qwen-max', 'system_fingerprint': None, 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-055fb3d0-6bf7-45d0-a237-ee8a4938fa15-0', tool_calls=[{'name': 'sql_db_query', 'args': {'query': \"SELECT id, sp_id, name, description, status, DATE_FORMAT(created_at, '%Y-%m-%d %H:%i:%s') as created_at FROM agent ORDER BY created_at DESC LIMIT 5;\", 'col_desc': {'id': '智能体ID', 'sp_id': '企业ID', 'name': '智能体名称', 'description': '描述', 'status': '状态', 'created_at': '创建时间'}}, 'id': 'call_811333299a1d440e91c9a7', 'type': 'tool_call'}], usage_metadata={'input_tokens': 11698, 'output_tokens': 182, 'total_tokens': 11880, 'input_token_details': {}, 'output_token_details': {}})]}}\n",
      "Assistant: \n",
      "col_desc: {'id': '智能体ID', 'sp_id': '企业ID', 'name': '智能体名称', 'description': '描述', 'status': '状态', 'created_at': '创建时间'}\n",
      "Event:{'query_execute_tools': {'messages': [ToolMessage(content=\"[{'id': 'fe6e3c61d1a74b2bb0942f202411271645', 'sp_id': '19080110203420013520', 'name': '短信数据智能客户3.0', 'description': '提供全面的数据查询、统计分析服务', 'status': 'normal', 'created_at': '2024-11-27 16:45:44'}, {'id': 'fe6e3c61d1a74b2bb0942f202411251035', 'sp_id': '19080110203420013520', 'name': '销售数据智能客户3.0', 'description': '提供全面的数据查询、统计分析服务', 'status': 'normal', 'created_at': '2024-11-25 10:31:01'}, {'id': '1e9eb96bc1c34fe499bbc7b87af43120', 'sp_id': '230227193624036681', 'name': '我是数据查询专家', 'description': '你可以向我提出数据查询要求，我会为你生成sql并执行，返回查询数据给你', 'status': 'normal', 'created_at': '2024-11-20 10:04:32'}, {'id': '86cdf4983f3f4a08843ce76c210718f0', 'sp_id': '19080110203420013520', 'name': '短信知识问答', 'description': '为您解答各种操作、开发问题', 'status': 'normal', 'created_at': '2024-11-15 13:44:19'}, {'id': 'fe6e3c61d1a74b2bb0942f4404ca1234', 'sp_id': '19080110203420013520', 'name': '经分助手智能客户3.0', 'description': '', 'status': 'normal', 'created_at': '2024-11-12 14:53:53'}]\", name='sql_db_query', id='5fe2b302-90be-4266-8380-613c6df9aa49', tool_call_id='call_811333299a1d440e91c9a7')]}}\n",
      "Assistant: [{'id': 'fe6e3c61d1a74b2bb0942f202411271645', 'sp_id': '19080110203420013520', 'name': '短信数据智能客户3.0', 'description': '提供全面的数据查询、统计分析服务', 'status': 'normal', 'created_at': '2024-11-27 16:45:44'}, {'id': 'fe6e3c61d1a74b2bb0942f202411251035', 'sp_id': '19080110203420013520', 'name': '销售数据智能客户3.0', 'description': '提供全面的数据查询、统计分析服务', 'status': 'normal', 'created_at': '2024-11-25 10:31:01'}, {'id': '1e9eb96bc1c34fe499bbc7b87af43120', 'sp_id': '230227193624036681', 'name': '我是数据查询专家', 'description': '你可以向我提出数据查询要求，我会为你生成sql并执行，返回查询数据给你', 'status': 'normal', 'created_at': '2024-11-20 10:04:32'}, {'id': '86cdf4983f3f4a08843ce76c210718f0', 'sp_id': '19080110203420013520', 'name': '短信知识问答', 'description': '为您解答各种操作、开发问题', 'status': 'normal', 'created_at': '2024-11-15 13:44:19'}, {'id': 'fe6e3c61d1a74b2bb0942f4404ca1234', 'sp_id': '19080110203420013520', 'name': '经分助手智能客户3.0', 'description': '', 'status': 'normal', 'created_at': '2024-11-12 14:53:53'}]\n",
      "delete_messages: 7\n",
      "Event:{'delete_messages': {'messages': [RemoveMessage(content='', additional_kwargs={}, response_metadata={}, id='1d5eda7f-d92e-4369-8911-00b733650c02'), RemoveMessage(content='', additional_kwargs={}, response_metadata={}, id='run-cbe07aca-d850-4477-b6d1-ee7a86a051bb-0'), RemoveMessage(content='', additional_kwargs={}, response_metadata={}, id='1745a8c4-61cd-4203-bac2-46adfe3c441d'), RemoveMessage(content='', additional_kwargs={}, response_metadata={}, id='230f4519-a63c-453f-9b2f-2ac9960b9093')]}}\n",
      "Assistant: \n"
     ]
    }
   ],
   "source": [
    "from langchain_core.messages import BaseMessage\n",
    "\n",
    "# graph.invoke({\"messages\": [(\"user\", \"我需要10人生日是1970年之前的员工\")]})\n",
    "config = {\"configurable\": {\"thread_id\": \"3\"}}\n",
    "\n",
    "for event in graph.stream(\n",
    "    {\"messages\": [(\"user\", \"查询智能体\")]},config\n",
    "):\n",
    "    print(f\"Event:{event}\")\n",
    "    # if msg.content and isinstance(msg, AIMessage):\n",
    "    #     print(\"Assistant:\", msg.content)\n",
    "    for value in event.values():\n",
    "            if isinstance(value[\"messages\"][-1], BaseMessage):\n",
    "                print(\"Assistant:\", value[\"messages\"][-1].content)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-12-06T09:56:27.041996Z",
     "start_time": "2024-12-06T09:56:03.164695Z"
    }
   },
   "id": "b458181c6323b79a",
   "execution_count": 30
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "3"
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "messages = graph.get_state(config).values[\"messages\"]\n",
    "len(messages)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-12-06T09:55:56.141126Z",
     "start_time": "2024-12-06T09:55:56.132040Z"
    }
   },
   "id": "512c67620ae528fc",
   "execution_count": 28
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
